﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Threading;

namespace Topro.Service
{
    using NLog;
    using Topro.Application;
    using Topro.Entity;
    using Topro.Entity.Query;
    using Topro.Enum;
    using Topro.Libraries.Util;
    using Topro.Monitor;

    /// <summary>
    /// 垛机
    /// </summary>
    public class AppService
    {
        #region 变量
        /// <summary>
        /// 消息委托
        /// </summary>
        public delegate void InfoDelegate(int type, Dictionary<string, string> dc);

        /// <summary>
        /// 消息事件
        /// </summary>
        public event InfoDelegate infoEvent;

        /// <summary>
        /// 站台消息委托
        /// </summary>
        public delegate void StationDelegate(int station, int status);

        /// <summary>
        /// 站台消息事件
        /// </summary>
        public event StationDelegate stationEvent;

        /// <summary>
        /// 读码器
        /// </summary>
        public List<BCRStation> bcrStations = null;

        /// <summary>
        /// 堆垛
        /// </summary>
        public Stacker stacker = null;

        /// <summary>
        /// 入库暂存站台
        /// </summary>
        public List<StockStation> stockStations { get; set; }

        /// <summary>
        /// 扫码线程
        /// </summary>
        private Thread scanThread = null;

        /// <summary>
        /// 扫码器
        /// </summary>
        private List<TcpClientUtil> tcpClientUtils = null;

        /// <summary>
        /// 日志
        /// </summary>
        private static readonly Logger logScan = LogManager.GetLogger("Scan");
        #endregion

        #region 初始化
        public void init()
        {
            #region 异常
            var deviceExceptionCodeListQuery = new DeviceExceptionCodeListQuery()
            {
                MachineCode = 1
            };
            var deviceExceptionCode = DeviceExceptionCodeApp.Instance.GetList(deviceExceptionCodeListQuery);
            #endregion

            #region 读码器
            //获取指令列有
            string bcrStationFilePath = $"{System.Environment.CurrentDirectory}\\BCRStation.xml";
            //获取xml内容
            var outInStationXml = Libraries.Util.FileUtil.loadFile(bcrStationFilePath);
            //序列化
            bcrStations = Libraries.Util.SerializationUtil.XmlDeserialize<List<BCRStation>>(outInStationXml);
            #endregion

            #region 堆垛机
            //获取指令列有
            string stockStationPath = $"{System.Environment.CurrentDirectory}\\StockStation.xml";
            //获取xml内容
            var stockStationXml = Libraries.Util.FileUtil.loadFile(stockStationPath);
            //序列化
            stockStations = Libraries.Util.SerializationUtil.XmlDeserialize<List<StockStation>>(stockStationXml);

            stacker = new Stacker();
            stacker.stockStations = stockStations;
            stacker.inStockStations = stockStations.Where(c => c.Type == (int)WorkStatus.One).ToList();
            stacker.outStockStations = stockStations.Where(c => c.Type == (int)WorkStatus.Two).ToList();
            stacker.deviceExceptionCode = deviceExceptionCode;
            //堆垛机
            stacker.infoEvent += new Stacker.InfoDelegate(Info);
            stacker.stationEvent += new Stacker.StationDelegate(Station);

            //输送线
            stacker.transLineStationNumber = int.Parse(ConfigurationManager.AppSettings["transLineStationNumber"]);

            if (stacker.transLineUtil == null)
                stacker.transLineUtil = new PlcUtil(stacker.transLineStationNumber);

            if (stacker.transLineUtil.connectStatus == ConnectStatus.Opened)
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"输送线({stacker.transLineStationNumber})启动成功" });
            else
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"输送线({stacker.transLineStationNumber})启动失败" });
            //堆垛机
            stacker.stackerStationNumber = int.Parse(ConfigurationManager.AppSettings["stackerStationNumber"]);

            if (stacker.stackerUtil == null)
                stacker.stackerUtil = new PlcUtil(stacker.stackerStationNumber);

            if (stacker.stackerUtil.connectStatus == ConnectStatus.Opened)
            {
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"堆垛机({stacker.stackerStationNumber})启动成功" });

                stacker.stackerThread = new Thread(stacker.main);
                stacker.stackerThread.IsBackground = true;
                stacker.stackerThread.Start();
            }
            else
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"堆垛机({stacker.stackerStationNumber})启动失败" });
            #endregion

            #region 扫码
            scanThread = new Thread(scan);
            scanThread.Start();
            #endregion
        }
        #endregion

        #region 扫码器
        /// <summary>
        /// 初始化扫码器
        /// </summary>
        public void scan()
        {
            //初始化对象大小
            tcpClientUtils = new List<TcpClientUtil>();

            if (bcrStations != null && bcrStations.Any())
            {
                foreach (var item in bcrStations)
                {
                    var tcpClientUtil = new TcpClientUtil(item.ServerIp, item.ServerProt);
                    //委托
                    tcpClientUtil.MessageEvent += new TcpClientUtil.MessageDelegate(Scan);

                    tcpClientUtils.Add(tcpClientUtil);

                    infoEvent(0, new Dictionary<string, string> { ["1"] = $"读码器({item.Id}->{item.ServerIp}->{item.ServerProt})连接成功." });
                }
            }
        }

        /// <summary>
        /// 获取扫码
        /// </summary>
        /// <param name="_tPackMes"></param>
        public void Scan(string message)
        {
            try
            {
                if (!string.IsNullOrEmpty(message))
                {
                    logScan.Info($"[扫码][{message}]");
                    //infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][{message}]" });

                    if (message == "ConSuccessful")
                        return;
                    //扫码转换为数量、
                    var array = message.Split(':');
                    //验证数组大小
                    if (array.Length != 2)
                    {
                        logScan.Info($"[扫码][格式有误({message})]");
                        //infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][格式有误({message})]" });
                        return;
                    }

                    //验证无记录
                    if (array[1].Contains("ERROR"))
                    {
                        logScan.Info($"[扫码][获取托盘编码失败({array[1]})]");
                        //infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][获取托盘编码失败({array[1]})]" });
                        return;
                    }
                    //编号
                    var id = 0;
                    //转换
                    int.TryParse(Regex.Replace(array[0], @"[\r\n]", ""), out id);
                    //容器
                    string qrCode = Regex.Replace(array[1], @"[\r\n]", "");
                    //设置
                    var stockStation = stockStations.FirstOrDefault(c => c.Id == id);
                    if (stockStation != null)
                    {
                        infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置流水号({stockStation.SerialNoAddr}->{qrCode})]" });

                        if (stacker.transLineUtil != null)
                        {
                            int result = stacker.transLineUtil.Set(stockStation.SerialNoAddr, id);
                            if (result == -1)
                                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置流水号失败]" });
                            else
                                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置站台流水号成功]" });
                        }
                        else
                            infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][设置流水号(输送线对象为空)]" });
                    }
                }
                else
                    infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][获取托盘码内容为空]" });
            }
            catch (Exception ex)
            {
                infoEvent(0, new Dictionary<string, string> { ["1"] = $"[扫码][扫码异常:{ex.Message}]" });
            }
        }
        #endregion

        #region 设置站号
        /// <summary>
        /// 设置站号
        /// </summary>
        /// <param name="stationId">站号</param>
        public void SetStation(int stationId, int containerCode)
        {
            stacker.SetStation(stationId, containerCode);
        }
        #endregion

        #region 事件消息
        /// <summary>
        /// 事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="info"></param>
        public void Info(int type, Dictionary<string, string> dc)
        {
            if (infoEvent != null)
                infoEvent(type, dc);
        }

        /// <summary>
        /// 站台事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="workStatus"></param>
        /// <param name="info"></param>
        public void Station(int station, int status)
        {
            if (stationEvent != null)
                stationEvent(station, status);
        }

        /// <summary>
        /// 站台事件消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="workStatus"></param>
        /// <param name="info"></param>
        public void TwoStation(int station, int status)
        {
            if (stationEvent != null)
                stationEvent(station, status);
        }
        #endregion

        #region 复原
        /// <summary>
        /// 复原
        /// </summary>
        /// <returns></returns>
        public JResult Restore()
        {
            return stacker.Restore();
        }
        #endregion

        #region 释放
        /// <summary>
        /// 释放
        /// </summary>
        public void close()
        {
            if (scanThread != null)
                scanThread.Abort();
            scanThread = null;

            if (tcpClientUtils.Any())
            {
                foreach (TcpClientUtil tcpClientUtil in tcpClientUtils)
                {
                    tcpClientUtil.close();
                }
                tcpClientUtils.Clear();
            }

            tcpClientUtils = null;
            if (stacker != null)
                stacker.Dispose();
            stacker = null;

        }
        #endregion

        #region 清空
        /// <summary>
        /// 清空
        /// </summary>
        /// <returns></returns>
        public JResult Clear()
        {
            return null;
            //return oneStacker.Clear();
        }
        #endregion
    }
}
